package com.atguigu.gulimall.cart.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.atguigu.common.utils.R;
import com.atguigu.gulimall.cart.feign.ProductFeignService;
import com.atguigu.gulimall.cart.interceptor.CartInterceptor;
import com.atguigu.gulimall.cart.service.CartService;
import com.atguigu.gulimall.cart.vo.Cart;
import com.atguigu.gulimall.cart.vo.CartItem;
import com.atguigu.gulimall.cart.vo.SkuInfoVo;
import com.atguigu.gulimall.cart.vo.UserInfoTo;
import com.sun.deploy.uitoolkit.impl.text.FXAppContext;
import com.sun.org.apache.xalan.internal.res.XSLTErrorResources_ko;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.javassist.bytecode.stackmap.BasicBlock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.thymeleaf.engine.ISSEThrottledTemplateWriterControl;
import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;
@Slf4j
@Service
public class CartServiceImpl implements CartService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private ProductFeignService productFeignService;
    @Autowired
    private ThreadPoolExecutor executor;
    private final  String CART_PREFIX= "gulimall:cart:";
    @Override
    public CartItem addToCart(Long skuId, Integer num) throws ExecutionException, InterruptedException {
//
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();  //  获取绑定的hash操作
        String res= (String) cartOps.get(skuId.toString());   // 根据key获取value   根据skuId 获取res  ,res代表的sku详细信息
        if(StringUtils.isEmpty(res)){    //  如果res是空的
            //            远程查询当前要添加的商品信息
            CartItem cartItem = new CartItem();   //  这个是购物车的每一项, 不是整个购物车
            CompletableFuture<Void> getSkuInfoTask= CompletableFuture.runAsync(() -> {
                R skuInfo = productFeignService.getSkuInfo(skuId); //  远程调用商品服务, 根据skuId,获取sku详细信息
                SkuInfoVo skuInfo1 = skuInfo.getData("skuInfo", new TypeReference<SkuInfoVo>() {});
                cartItem.setCheck(true); //  赋值
                cartItem.setCount(num);  // 赋值
                cartItem.setImage(skuInfo1.getSkuDefaultImg()); // 赋值
                cartItem.setTitle(skuInfo1.getSkuTitle()); //赋值
                cartItem.setSkuId(skuId);// 赋值
                cartItem.setPrice(skuInfo1.getPrice());//赋值:
            }, executor);
            CompletableFuture<Void> getSkuSaleAttrValues = CompletableFuture.runAsync(() -> {
//获取sku的销售属性
                List<String> skuSaleAttrValues = productFeignService.getSkuSaleAttrValues(skuId); //获取销售属性
                cartItem.setSkuAttr(skuSaleAttrValues);
            }, executor);
            CompletableFuture.allOf(getSkuInfoTask,getSkuSaleAttrValues).get();
            String jsonString = JSON.toJSONString(cartItem);
            cartOps.put(skuId.toString(),jsonString);
            return  cartItem;
        }
        else{
            //  说明 购物车 有这个东西, 那我就 修改数量
            CartItem cartItem = JSON.parseObject(res, CartItem.class);
            cartItem.setCount(cartItem.getCount()+num);
            cartOps.put(skuId.toString(),JSON.toJSONString(cartItem));
        return cartItem;
        }
    }
/*
方法作用:获取购物车里面某个购物项
 */
    @Override
    public CartItem getCartItem(Long skuId) {
        BoundHashOperations<String,Object,Object> cartOps=getCartOps();
String  string= (String) cartOps.get(skuId.toString());
        CartItem cartItem = JSON.parseObject(string, CartItem.class);
        return cartItem;
    }
    @Override
    public Cart getCart() throws ExecutionException, InterruptedException {
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();// 从拦截器里面获取用户信息
        Cart cart = new Cart(); //   创建  购物车  对象
        if (userInfoTo.getUserId() != null) {//登录了
            String cartKey=CART_PREFIX+ userInfoTo.getUserId();  //gulimall:cart:
        //  如果, 临时购物车的数据还没有进行合并
            String tempCartKey =  CART_PREFIX+userInfoTo.getUserKey();
            List<CartItem> tempCartItems = getCartItems(CART_PREFIX + userInfoTo.getUserKey());
            if (tempCartItems!=null){//说明临时购物车有数据,需要合并.
                for (CartItem tempCartItem : tempCartItems) {
                addToCart(tempCartItem.getSkuId(),tempCartItem.getCount());
                }
                clearCart(tempCartKey);//  清除临时购物车数据
            }
            List<CartItem> cartItems = getCartItems(cartKey);// 包含合并过来的临时购物车数据
            cart.setItems(cartItems);
        }else {//没有登录
            String cartKey=CART_PREFIX+ userInfoTo.getUserKey();
            List<CartItem> cartItems = getCartItems(cartKey);
            cart.setItems(cartItems);
        }
        return cart;
    }
    /*
    获取到我们要操作的购物车
     */
    private BoundHashOperations<String, Object, Object> getCartOps() {    //获取一个车子  ,去那里领取一个车子
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();  // 获取登录的用户信息
        String   cartKey="";
        if(userInfoTo.getUserId()!=null) {    //说明用户登录了
            cartKey  =  CART_PREFIX +  userInfoTo.getUserId();   //  示例:gulimall:cart:999
        }else{  //  说明用户没有登录
            cartKey=    CART_PREFIX   +  userInfoTo.getUserKey();
        }
        BoundHashOperations<String, Object, Object>   hashRedisBinding = stringRedisTemplate.boundHashOps(cartKey);  //绑定hash操作
        return hashRedisBinding;  //返回绑定的hash操作
    }
    private List<CartItem>  getCartItems(String cartKey){    //   从redis获取购物车信息
        BoundHashOperations<String, Object, Object> hashOps= stringRedisTemplate.boundHashOps(cartKey);
        List<Object> values = hashOps.values();
        if (values != null  &&  values.size()>0) {
            List<CartItem> collect = values.stream().map(obj -> {
                String str=(String) obj;
                CartItem cartItem1 = JSON.parseObject(str, CartItem.class);
                return cartItem1;
            }).collect(Collectors.toList());
        return   collect;
        }
        return null;
    }
    @Override
    public void clearCart(String cartKey){
        stringRedisTemplate.delete(cartKey);
    }
/*
勾选购物项
 */
    @Override
    public void checkItem(Long skuId, Integer check) {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        CartItem cartItem = getCartItem(skuId);
        cartItem.setCheck(check==1?true:false);
        String jsonString = JSON.toJSONString(cartItem);
        cartOps.put(skuId.toString(),jsonString);
    }
    @Override
    public void changeItemCount(Long skuId, Integer num) {
        CartItem cartItem = getCartItem(skuId);
        cartItem.setCount(num);
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        cartOps.put(skuId.toString(),JSON.toJSONString(cartItem));
    }
    @Override
    public void deleteItem(Long skuId) {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        cartOps.delete(skuId.toString());
    }
    @Override
    public List<CartItem> getUserCartItems() {
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();  //  获取用户信息
        if(userInfoTo.getUserId()==null){  // 如果用户为空,返回空值
        return null;  //
        }else{ //   如果不为空
            String cartKey=CART_PREFIX+userInfoTo.getUserId(); //gulimall:cart:
            List<CartItem> cartItems = getCartItems(cartKey);
            List<CartItem> collect = cartItems.stream().filter(one ->
                    one.getCheck()).
                    map( one -> {
                        /*
                        更新为最新价格
                         */
                        R price = productFeignService.getPrice(one.getSkuId());
                        String o = (String) price.get("data");
                        one.setPrice(new BigDecimal(o));
                        return one;
                    }).
                    collect(Collectors.toList());
            return  collect;
        }
    }
}
